<?php

/**
 * Recursively strip all slashes in the provided variable
 * This function was added externally, mainly because I have no clue
 * how to recursivly call it internally using array_map
 *
 * @param string $value
 * @return string
 */
function stripslashes_deep($value) {
    $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
    return $value;
}

class Request {

    /**
     * Why SOAP is a bad webservice:
     *  At the very end of this class are documentation functions that print example
     *  output that is pulled from final version functions. Using the following formula:
     *
     *  % = (contentSizeXML - contentSizeJSON) / contentSizeJSON * 100
     *
     *  I came up with an average percentage that XML exceeded the JSON return type of
     *  my personal API for this project. The resulting numbers were:
     *
     *  36,78,36,61,133,138,84
     *  Average = 80.857% increase in return data
     *
     *  This is expected due to the structure of XML since every return is encapsulated
     *  within its identifier. But I would like to point out that
     *  my API only returns an XML document. So this 80% increase in data return is just
     *  a pure data increase; this is WITHOUT required SOAP headers for SOAP based APIs.
     *
     *  So not only can you access my API with simple HTTP GET requests, bypassing the
     *  retarded and REQUIRED SOAP headers, you save tons of data just asking for the
     *  JSON return type. I'm willing to bet if you added the SOAP response to my XML
     *  you would be requesting 100% more data than my standard response.
     *
     *  So you save time in development by issuing simple HTTP requests, you save
     *  bandwidth during transfer to and from the API, and you save processing time
     *  of the final return type. Why on earth do you use SOAP for this project?
     */

    /*
     * Generic object variables
     */
    private $version = '0.98.0';
    private $docv = '1.98';
    private $auth = 'generic';
    private $type;

    /*
     * Database connection settings
     */
    private $connection = 'mssql';
    private $db = 'CampusMaps';
    private $server = 'MGRIDHOST';
    private $user = 'mapagent';
    private $password = 'cpscmaps';

    /*
     * Campus GPS locations
     */
    private $north = array();
    private $east = array();
    private $south = array();
    private $west = array();

    /*
     * Coordinates to 10ft ratio
     *
     * North-most Clemson: 34.6836,-82.8377
     * East-most Clemson: 34.6759,-82.8182
     * South-most Clemson: 34.6676,-82.8384
     * West-most Clemson: 34.6786,-82.8572

     * Difference top to bottom: 0.0160
     * ~2km high
     * 0.0160/2000 = .000008d/m
     * ~10ft    0.000008 * 3 = 0.000024
     *
     * Difference left to right: 0.0390
     * ~4km across
     * 0.0390/4000 = 0.00000975d/m
     * ~10ft	0.00000975 * 3 = 0.00002925
     */
    private $n_to_s = '0.000024';
    private $e_to_w = '0.00002925';

    private $sid;
    private $method;
    private $body;

    private $xmlwrapper = "node";

    /*
     * Arguments allowed after creation
     */
    var $debug = false;
    var $minimal = false;
    var $order = 'id';
    var $category = 'first';
    // used for JSONP response
    var $callback;
    // used for closest pathing
    var $destination;


    /**
     * Default constructor. By default uses generic auth with a json return type
     *
     * @param string $auth
     * @param string $method
     * @param string $t
     */
    function  __construct($auth,$method,$t) {
        if(!empty($auth))
            $this->auth = $auth;

        if(empty($t)) {
            $this->type = "json";
        } else {
            $this->type = $t;
        }
        $this->method = $method;
    }

    /**
     * Return the application mime type
     *
     * @param string $type
     * @return string
     */
    private function __content($type) {
        $types = Array(
                'text' => 'text/html',
                'json' => 'application/json',
                'xml'  => 'application/xml'
        );
        return (isset($types[$type])) ? $types[$type] : '';
    }

    /**
     * Return the HTTP response code text
     *
     * @param string $status
     * @return string
     */
    private function __httpstatus($status) {
        $codes = Array(
                100 => 'Continue',
                101 => 'Switching Protocols',
                200 => 'OK',
                201 => 'Created',
                202 => 'Accepted',
                203 => 'Non-Authoritative Information',
                204 => 'No Content',
                205 => 'Reset Content',
                206 => 'Partial Content',
                300 => 'Multiple Choices',
                301 => 'Moved Permanently',
                302 => 'Found',
                303 => 'See Other',
                304 => 'Not Modified',
                305 => 'Use Proxy',
                306 => 'Unrecognized argument',
                307 => 'Temporary Redirect',
                400 => 'Bad Request',
                401 => 'Unauthorized',
                402 => 'Payment Required',
                403 => 'Forbidden',
                404 => 'Not Found',
                405 => 'Method Not Allowed',
                406 => 'Not Acceptable',
                407 => 'Proxy Authentication Required',
                408 => 'Request Timeout',
                409 => 'Conflict',
                410 => 'Gone',
                411 => 'Length Required',
                412 => 'Precondition Failed',
                413 => 'Request Entity Too Large',
                414 => 'Request-URI Too Long',
                415 => 'Unsupported Media Type',
                416 => 'Requested Range Not Satisfiable',
                417 => 'Expectation Failed',
                500 => 'Internal Server Error',
                501 => 'Not Implemented',
                502 => 'Bad Gateway',
                503 => 'Service Unavailable',
                504 => 'Gateway Timeout',
                505 => 'HTTP Version Not Supported',

                508 => 'No such edge',
                509 => 'No such node',
                510 => 'No nodes in category'
        );
        return (isset($codes[$status])) ? $codes[$status] : '';
    }

    /**
     * Default function wrapper
     *
     * @param string $name
     * @param array $args
     * @return NULL
     */
    function  __call($name, $args) {
        // can cause server to return 501        
        if(method_exists(self,$name)) {
            $this->$name($args);
        }
        return;
    }

    /**
     * Encode the body of the response to the desired type
     *
     * @param array $object
     * @return string
     */
    private function __encodebody($object) {
        switch($this->type) {
            case 'json':
                $return = $this->arraytojson($object);
                break;
            case 'xml':
                $return = $this->arraytoxml($object);
                break;
            default:
                $return = $this->arraytotext($object);
                break;
        }
        return $return;
    }

    /**
     * Change the array values into text delimited response
     *
     * @param array $array
     * @return string
     */
    private function arraytotext(array $array) {
        $return = '';
        foreach($array AS $key => $value ) {
            if(is_array($value)) {
                $return .= $this->arraytotext($value);
            }else {
                if (is_numeric($value) && !is_string($value)) {
                    $value = $value;
                } elseif(is_bool($value)) {
                    $value = ( $value ? 'true' : 'false' );
                } elseif( $value === null ) {
                    $value = 'null';
                } else {
                    $value = '"' . addslashes($value) . '"';
                }
                $return .= "${key}: ${value}";
                $return .= ",";
            }
        }
        $return = substr($return, 0,-2);
        return $return;
    }

    /**
     * Change the array values into a JSON response string
     *
     * @param array $array
     * @return string
     */
    private function arraytojson(array $array) {
        $parts = array();
        $is_list = false;

        if (count($array)>0) {

            $keys = array_keys($array);
            $max_length = count($array)-1;
            if(($keys[0] === 0) and ($keys[$max_length] === $max_length)) {
                $is_list = true;
                for($i=0; $i<count($keys); $i++) {
                    if($i !== $keys[$i]) {
                        $is_list = false;
                        break;
                    }
                }
            }

            foreach($array as $key=>$value) {
                $str = ( !$is_list ? '"' . $key . '":' : '' );
                if(is_array($value)) {
                    $parts[] = $str . $this->arraytojson($value);
                } else {
                    if (is_numeric($value) && !is_string($value)) {
                        $str .= $value;
                    } elseif(is_bool($value)) {
                        $str .= ( $value ? 'true' : 'false' );
                    } elseif( $value === null ) {
                        $str .= 'null';
                    } else {
                        $str .= '"' . addslashes($value) . '"';
                    }
                    $parts[] = $str;
                }
            }
        }
        $json = implode(",",$parts);

        if($is_list) return '[' . $json . ']';
        return '{' . $json . '}';
    }

    function arraytoxml($array, $level=1) {
        $xml = '';
        if ($level==1) {
            $xml .= '<?xml version="1.0" encoding="ISO-8859-1"?>'."\n<root>\n";
        }
        foreach ($array as $key=>$value) {
            $key = strtolower($key);
            if (is_array($value)) {
                $multi_tags = false;
                foreach($value as $key2=>$value2) {
                    if (is_array($value2)) {
                        if($level == 1) {
                            $print = $this->xmlwrapper;
                        } else {
                            $print = $key;
                        }

                        $xml .= str_repeat("\t",$level)."<$print>\n";
                        $xml .= $this->arraytoxml($value2, $level+1);
                        $xml .= str_repeat("\t",$level)."</$print>\n";
                        $multi_tags = true;
                    } else {
                        if (trim($value2)!='') {
                            if (htmlspecialchars($value2)!=$value2) {
                                $xml .= str_repeat("\t",$level).
                                "<$key><![CDATA[$value2]]>".
                                "</$key>\n";
                            } else {
                                $xml .= str_repeat("\t",$level).
                                "<$key>$value2</$key>\n";
                            }
                        }
                        $multi_tags = true;
                    }
                }
                if (!$multi_tags and count($value)>0) {
                    $xml .= str_repeat("\t",$level)."<$key>\n";
                    $xml .= $this->arraytoxml($value, $level+1);
                    $xml .= str_repeat("\t",$level)."</$key>\n";
                }
            } else {
                if (trim($value)!='') {
                    if (htmlspecialchars($value)!=$value) {
                        $xml .= str_repeat("\t",$level)."<$key>".
                        "<![CDATA[$value]]></$key>\n";
                    } else {
                        $xml .= str_repeat("\t",$level).
                        "<$key>$value</$key>\n";
                    }
                }
            }
        }
        if ($level==1) {
            $xml .= "</root>\n";
        }
        return $xml;
    }

    /**
     * Absolutly nothing yet :D
     *
     * @return string
     */
    private function  __toString() {
        // TODO: remove function calls and just have printable object
        return print_r($this,true);
    }

    /**
     * Build the response to the user and then display it
     * Object ends itself here
     *
     * @param string $status
     */
    private function respond($status="200") {
        // set the status message
        $message = $this->__httpstatus($status);
        // set the content type
        $content = $this->__content($this->type);
        // clean the body from the database
        $this->body = stripslashes_deep($this->body);

        // build header
        $s_header = "HTTP/1.1 ${status} ${message}";
        if($this->debug) { // if debug, print instead of build
            echo "<pre>${s_header}\n";
        }
        else {
            // set status type in response
            header($s_header);
        }

        if( $status == "200" ) {
            if(!empty($this->body) && !$this->debug) {
                $c_header = "Content-Type: ${content}";
                // set content type in response
                header($c_header);
                // set the default filename in response
                header("Content-Disposition: attachment; filename=\"response\";");
                // encode body into return type
                $body = $this->__encodebody($this->body);                
                // if JSONP request set callback in response
                if(!empty($this->callback)) {
                    $body = $this->callback . '(' . $body . ')';
                } 
                $l_header = "Content-Length: ".strlen($body);
                // set content length in response
                header($l_header);
                echo $body;
            } else if(!empty($this->body) && $this->debug) {
                // this is a debug clause, just print the data don't return the response
                echo $c_header = "Content-Type: ${content}";
                echo "\n";
                $body = $this->__encodebody($this->body);
                if(!empty($this->callback)) {
                    $body = $this->callback . '(' . $body . ')';
                }
                echo $l_header = "Content-Length: ".strlen($body);
                echo "\n";                
                echo $body;
                echo "</pre>";
            }
        }

        exit();
    }

    /**
     *
     * Begin the database wrapper functions
     * They will autodetect mysql/mssql and call the appropriate
     * built-in function
     *
     */

    /**
     * Connect to the database
     */
    private function connect() {
        switch($this->connection) {
            case "mssql":
                $this->sid = @mssql_connect($this->server, $this->user, $this->password);
                if(!$this->sid || !mssql_select_db($this->db,$this->sid) ) {
                    $status = '500';
                    $this->respond($status);
                }
                break;
            case "mysql":
                $this->sid = @mysql_connect($this->server, $this->user, $this->password);
                if(!$this->sid || !mysql_select_db($this->db,$this->sid) ) {
                    $status = '500';
                    $this->respond($status);
                }
                break;
        }
    }

    /**
     * Run the string as a database query
     *
     * @param string $query
     * @return SQL Result
     */
    private function query($query) {
        switch ($this->connection) {
            case "mssql":
                return @mssql_query($query);
                break;
            case "mysql":
                return @mysql_query($query);
                break;
        }
    }

    /**
     * Free the memory used containing the SQL Result
     *
     * @param SQL Result $result
     * @return boolean
     */
    private function free_result($result) {
        switch ($this->connection) {
            case "mssql":
                return @mssql_free_result($result);
                break;
            case "mysql":
                return @mysql_free_result($result);
                break;
        }
    }

    /**
     * Return an associative array of results
     *
     * @param SQL Result $result
     * @return array
     */
    private function fetch_assoc($result) {
        switch ($this->connection) {
            case "mssql":
                return @mssql_fetch_assoc($result);
                break;
            case "mysql":
                return @mysql_fetch_assoc($result);
                break;
        }
    }

    /**
     * Return an integer of the number of rows returned in the result
     *
     * @param SQL Result $result
     * @return integer
     */
    private function num_rows($result) {
        switch ($this->connection) {
            case "mssql":
                return @mssql_num_rows($result);
                break;
            case "mysql":
                return @mysql_num_rows($result);
                break;
        }
    }


    /**
     *
     * Begin the API processing functions
     *
     */


    /**
     * Set the body to contain nothing but the API version
     */
    function getversion() {
        $status = '200';
        $this->body = array("Version"=>$this->version);
        $this->respond($status);

    }

    /**
     * Return a list of all the nodes in the database
     */
    function getlistnodes() {
        $status = '200';
        $this->connect();

        $order = $this->order; // get order flag
        $result = $this->query("SELECT * FROM mapNodes ORDER BY $order ASC");

        if($this->minimal) { // is minimal set?
            while($row = $this->fetch_assoc($result)) {
                if($this->type == 'xml') {
                    $this->body[] = array( "node" => array( "id" => $row['id'], "Name" => stripslashes($row['name']), "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] ));
                } else {
                    $this->body[] = array( "id" => $row['id'], "Name" => stripslashes($row['name']), "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] );
                }
            }
        } else { // default output
            while($row = $this->fetch_assoc($result)) {
                if($this->type == 'xml') {
                    $this->body[] = array( "node" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'] ));
                } else {
                    $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'] );
                }
            }
        }
        $this->free_result($result);
        $this->respond($status);
    }

    /**
     * Return the details of a specific node
     *
     * @param integer $num
     */
    function getnode($num) {
        $status = '200';
        $this->connect();

        // no requested node
        if(empty($num)) {
            $this->respond('306');
        }

        $result = $this->query("SELECT * FROM mapNodes WHERE id = '$num'");

        if( $this->num_rows($result) ) {
            if(!$this->minimal) { // no minimal flag set
                // get all attached nodes
                $edges = $this->query("SELECT * FROM mapEdges WHERE firstnode = '$num' OR secondnode = '$num'");
                if( $this->num_rows($edges) ) { // if it has attached nodes process distance
                    while($row = $this->fetch_assoc($edges)) {
                        if( $row['firstnode'] == $num ) {
                            $node = $row['secondnode'];
                        } else {
                            $node = $row['firstnode'];
                        }

                        $a_edges[] = array( "id" => $row['id'], "Next" => $node, "Distance" => $row['distance'], "Handicap" => $row['handicap'] );
                    }
                }
                while($row = $this->fetch_assoc($result)) {
                    if($this->type == 'xml') {
                        $this->body[] = array( "node" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'], "Edges" => $a_edges ));
                    } else {
                        $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'], "Edges" => $a_edges );
                    }
                }
            } else { // minimal flag set
                while($row = $this->fetch_assoc($result)) {
                    if($this->type == 'xml') {
                        $this->body[] = array( "node" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] ));
                    } else {
                        $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] );
                    }
                }
            }
            $this->free_result($result);
        } else {
            $status = '509';
        }
        $this->respond($status);
    }

    /**
     * Return a list of all edges in the database
     */
    function getlistedges() {
        $status = '200';
        $this->xmlwrapper = 'edge';
        $this->connect();

        $result = $this->query("SELECT * FROM mapEdges");

        // This doesn't require a minimal option since all information is regarded
        // as important
        while($row = $this->fetch_assoc($result)) {
            if(!$this->minimal) {
                $first = $row['firstnode'];
                $r_first = $this->query("SELECT latitude, longitude FROM mapNodes WHERE id = '$first'");
                $s_first = $this->fetch_assoc($r_first);

                $second = $row['firstnode'];
                $r_second = $this->query("SELECT latitude, longitude FROM mapNodes WHERE id = '$second'");
                $s_second = $this->fetch_assoc($r_second);

                if($this->type == 'xml') {
                    $this->body[] = array( "edge" => array( "id" => $row['id'], "firstNodeID" => $row['firstnode'], "firstNodeLatitude" => $s_first['latitude'], "firstNodeLongitude"=> $s_first['longitude'], "secondNodeID" => $row['secondnode'], "secondNodeLatitude" => $s_second['latitude'], "secondNodeLongitude"=> $s_second['longitude'], "Distance" => $row['distance'], "Handicap" => $row['handicap'] ));
                } else {
                    $this->body[] = array( "id" => $row['id'], "firstNodeID" => $row['firstnode'], "firstNodeLatitude" => $s_first['latitude'], "firstNodeLongitude"=> $s_first['longitude'], "secondNodeID" => $row['secondnode'], "secondNodeLatitude" => $s_second['latitude'], "secondNodeLongitude"=> $s_second['longitude'], "Distance" => $row['distance'], "Handicap" => $row['handicap'] );
                }
            } else {
                if($this->type == 'xml') {
                    $this->body[] = array( "edge" => array( "id" => $row['id'], "firstNodeID" => $row['firstnode'], "secondNodeID" => $row['secondnode'], "Distance" => $row['distance'], "Handicap" => $row['handicap'] ));
                } else {
                    $this->body[] = array( "id" => $row['id'], "firstNodeID" => $row['firstnode'], "secondNodeID" => $row['secondnode'], "Distance" => $row['distance'], "Handicap" => $row['handicap'] );
                }
            }
        }
        $this->free_result($result);
        $this->respond($status);
    }

    /**
     * Return the details of a specific edge
     *
     * @param integer $num
     */
    function getedge($num) {
        $status = '200';
        $this->xmlwrapper = 'edge';
        $this->connect();

        if(empty($num)) {
            $this->respond('306');
        }
        $result = $this->query("SELECT * FROM mapEdges WHERE id = '$num'");

        // This doesn't require a minimal option since all information is regarded
        // as important
        if( $this->num_rows($result) ) {
            while($row = $this->fetch_assoc($result)) {
                if($this->type == 'xml') {
                    $this->body[] = array("edge" => array( "id" => $row['id'], "firstnode" => $row['firstnode'], "secondnode" => $row['secondnode'], "Distance" => $row['distance'], "Handicap" => $row['handicap'] ));
                } else {
                    $this->body[] = array( "id" => $row['id'], "firstnode" => $row['firstnode'], "secondnode" => $row['secondnode'], "Distance" => $row['distance'], "Handicap" => $row['handicap'] );
                }
            }
            $this->free_result($result);
        } else {
            $status = '508';
        }
        $this->respond($status);
    }

    /**
     * Return a list of all the nodes in a specific category
     * Category defined by ID number
     *
     * @param integer $type
     */
    function getcategory($type) {
        $status = '200';
        $this->connect();

        $order = $this->order;
        $result = $this->query("SELECT * FROM mapNodes WHERE category = '$type' ORDER BY $order ASC");

        if( $this->num_rows($result) ) {
            if($this->minimal) { // minimal flag set
                while($row = $this->fetch_assoc($result)) {
                    if($this->type == 'xml') {
                        $this->body[] = array( "category" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] ));
                    } else {
                        $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] );
                    }
                }
            } else {
                while($row = $this->fetch_assoc($result)) {
                    if($this->type == 'xml') {
                        $this->body[] = array( "category" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'] ));
                    } else {
                        $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'] );
                    }
                }
            }
            $this->free_result($result);
        } else {
            $status = '510';
        }
        $this->respond($status);
    }

    /**
     * Return a list of all category names
     */
    function getlistcategory() {
        $status = '200';
        $this->xmlwrapper = 'category';
        $this->connect();

        $result = $this->query("SELECT * FROM mapLocTypes");

        if( $this->num_rows($result) ) {
            while($row = $this->fetch_assoc($result)) {
                if($this->type == 'xml') {
                    $this->body[] = array( "category" => array( "id" => $row['id'], "Name" => $row['typename'] ));
                } else {
                    $this->body[] = array( "id" => $row['id'], "Name" => $row['typename'] );
                }
            }
            $this->free_result($result);
        } else {
            $status = '510';
        }
        $this->respond($status);
    }

    /**
     * Return a list of all the nodes in a specific category
     * Category defined by name
     *
     * @param string $name
     */
    function getcategoryname($name) {
        $status = '200';
        $this->xmlwrapper = 'category';
        $this->connect();

        $order = $this->order;
        $result = $this->query("SELECT * FROM mapLocTypes, mapNodes WHERE typename LIKE '$name' AND mapLocTypes.id = mapNodes.category ORDER BY mapNodes.$order ASC");

        if( $this->num_rows($result) ) {
            if($this->minimal) { // minimal flag is set
                while($row = $this->fetch_assoc($result)) {
                    if($this->type == 'xml') {
                        $this->body[] = array("node" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] ));
                    } else {
                        $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'] );
                    }
                }
            } else {
                while($row = $this->fetch_assoc($result)) {
                    if($this->type == 'xml') {
                        $this->body[] = array("node" => array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'] ));
                    } else {
                        $this->body[] = array( "id" => $row['id'], "Name" => $row['name'], "Longitude" => $row['longitude'], "Latitude" => $row['latitude'], "Category" => $row['category'], "Description" => $row['description'] );
                    }
                }
            }
            $this->free_result($result);
        } else {
            $status = '510';
        }
        $this->respond($status);
    }

    /**
     * Return the closest node(s) and their actual distances to the given
     * GPS coordinate
     *
     *  Haversine formula:
     *      R = earth’s radius (mean radius = 6,371km)
     *      Δlat = lat2− lat1
     *      Δlong = long2− long1
     *      a = sin²(Δlat/2) + cos(lat1)*cos(lat2)*sin²(Δlong/2)
     *      c = 2*atan2(√a, √(1−a))
     *      d = R*c*3280.8399
     *      d = distance in feet
     *
     *  Bearing formulat:
     *      θ =	atan2( sin(Δlong).cos(lat2), cos(lat1).sin(lat2) −
     *          sin(lat1).cos(lat2).cos(Δlong) )
     *
     *  Thanks to :
     *  http://www.movable-type.co.uk/scripts/latlong.html
     *
     * @param array $coordinate
     */
    function getclosest($coordinate) {
        $status = '200';
        $this->connect();

        $lat  = $coordinate[0];
        $long = $coordinate[1];

        if(empty($lat) || empty($long)) {
            $this->respond('306');
        }

        // increasing scan area from GPS coordinate
        $top = $long + $this->n_to_s;
        $bottom = $long - $this->n_to_s;
        $left = $lat - $this->e_to_w;
        $right = $lat + $this->e_to_w;

        if( $this->category == 'first' && empty($this->destination) ) {
            // select the first node, no matter what type it is from the db
            $extra = "";
        } else if( $this->category == 'main' && empty($this->destination) ) {
            // select the first main node, or non-pathnode, from the db
            $extra = "AND category > 0";
        } else if( !empty($this->destination) ) {
            // select the destination node from the db
            $result = $this->query("SELECT * FROM mapNodes WHERE id = $this->destination");
            if( $this->num_rows($result) == 0 ) { // this should protect against infinite while loops
                $this->respond('509');            // on non-existing destinations
            }
            $extra = "AND id = $this->destination";
        } else {
            // select the closest node of specified type from the db
            $result = $this->query("SELECT * FROM mapNodes WHERE category = '$this->category'");
            if( $this->num_rows($result) == 0 ) { // this should protect against infinite while loops
                $this->respond('510');            // on non-existing categories
            }
            $extra = "AND category = $this->category";
        }

        // select a node within the first 10 feet
        $result = $this->query("SELECT * FROM mapNodes WHERE longitude <= $top AND longitude >= $bottom AND latitude <= $right AND latitude >= $left $extra");

        // while you have 0 results within the scan area
        while( $this->num_rows($result) == 0 ) {
            
            // increase limits of scan
            $top += $this->n_to_s;
            $bottom -= $this->n_to_s;
            $left -= $this->e_to_w;
            $right += $this->e_to_w;

            $result = $this->query("SELECT * FROM mapNodes WHERE longitude <= $top AND longitude >= $bottom AND latitude <= $right AND latitude >= $left $extra");
        }

        // Haversine formula
        $e_radius = '6371'; // earths radius km
        $km_to_feet = '3280.8399'; // conversion ratio from km to feet

        while( $row = $this->fetch_assoc($result) ) {

            // distance
            $d_lat = (($lat - $row['latitude']) * M_PI / 180); // lat in radians
            $d_long = (($long - $row['longitude']) * M_PI / 180); // long in radians
            $a = sin($d_lat/2) * sin($d_lat/2) + cos(($lat * M_PI / 180)) * cos(($row['latitude'] * M_PI / 180)) * sin($d_long/2) * sin($d_long/2);
            $c = 2 * atan2(sqrt($a), sqrt(1-$a));
            $d = round(($e_radius * $c) * $km_to_feet);

            // bearing
            $y = sin($long-$row['longitude']) * cos($row["latitude"]);
            $x = cos($lat)*sin($row['latitude']) - sin($lat)*cos($row['latitude'])*cos($long-$row['longitude']);
            $i_bearing = rad2deg(atan2($y, $x));
            $f_bearing = ($i_bearing+360)%360;

            if($this->type == 'xml') {
                $this->body[] = array( "node" => array("id"=>$row['id'],"name"=>$row['name'],"longitude"=>$row['longitude'],"latitude"=>$row['latitude'],"category"=>$row['category'],"description"=>$row['description'],"distance"=>$d,"bearing"=>$f_bearing));
            } else {
                $this->body[] = array("id"=>$row['id'],"name"=>$row['name'],"longitude"=>$row['longitude'],"latitude"=>$row['latitude'],"category"=>$row['category'],"description"=>$row['description'],"distance"=>$d,"bearing"=>$f_bearing);
            }
        }
        $this->respond($status);
    }    

    /**
     *
     * Begin the documention display functions
     *
     */

    /*
     * The default HTML header
     */
    private function _header() {
        echo '<html>
             <head>
             <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
             <title>API Documentation v'.$this->docv.'</title>
             <style type="text/css">
                * {font-family:Tahoma, Arial, sans-serif;font-size:1em;}
                body {background:#fff;margin:.906em;font-size:69%;}
                h3 {font-size:1.5em;float:left;}
                div#container {background: #fff;width: 800px;margin: 0 auto;}
                div legend {color:#28f;font-weight:bold;margin:0 -5px;padding:0 5px 0 3px;}
                div fieldset {border:1px solid #ccc}
                div ul {list-style-type:none;margin:0;padding:0;}
                div ul li.header {font-size:2em;font-family:sans-serif;padding-top:10px;border-bottom:1px solid #f1f1f1;}
                div ul li {margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #f1f1f1;}
                div ul li label {font-size:2em;color:#aaa;width:100px;float:left;}
                ul.docs {float:left;width:210px;}
                ul.codes {float:right;margin-right:300px;clear:both;}
                a {text-decoration:none;cursor:pointer;color:#00f;}
                a:hover {text-decoration:underline;}
                .method {margin-left:210px;}
                div.method span {display:block;margin-bottom:5px;}
                .m_header {color:#28f;font-size:1.3em;}
                .request, .m_r {font-family:"Courier New",Courier,monospace;}
                .m_r {background:#f1f1f1;padding:3px;border:1px solid #000;margin-top:5px;}
                #version {color:#aaa;font-size:.6em;}
            </style>
            </head>
            <body>';
    }

    /*
     * The default menu on each page
     */
    private function _menu() {
        return '
            <ul class="docs">
                <li class="header"><a href="/">CampusMaps API</a><span id="version">'.$this->version.'</span></li>
                <li><label>Nodes</label><a href="/docs/listnodes">listnodes</a><br /><a href="/docs/node">node</a><br /><a href="/docs/category">category</a></li>
                <li><label>Edges</label><a href="/docs/listedges">listedges</a><br /><a href="/docs/edge">edge</a></li>
                <li><label>Other</label><a href="/docs/listcategory">listcategory</a><br /><a href="/docs/closest">closest</a></li>
            </ul>';
    }

    /*
     * The average response code listing
     */
    function gethelp() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     <ul class="codes">
                        <li class="header">Response Codes</li>
                        <li><label>200</label> Ok</li>
                        <li><label>306</label> Unrecognized argument</li>
                        <li><label>400</label> Bad Request</li>
                        <li><label>404</label> Not Found</li>
                        <li><label>500</label> Internal Error</li>
                        <li><label>508</label> No such edge</li>
                        <li><label>509</label> No such node</li>
                        <li><label>510</label> No nodes in category</li>
                     </ul>
                     '.$this->_menu().'
                     </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documention page for: getlistnodes()
     */
    function getdocslistnodes() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     '.$this->_menu().'
                     <div class="method">
                        <span class="m_header">listnodes</span>
                        <span class="request">http://api.hybridoptix.net/listnodes/[args]</span>
                        <span class="m_d"><strong>Description</strong><br/>Get a list of all nodes</span>
                        <span class="m_a"><strong>Arguments</strong><br/>
                        <dl>
                           <dt>boolean <u>&amp;debug</u></dt>
                              <dd>Pring return output in browser</dd>
                           <dt>boolean <u>&amp;minimal</u></dt>
                              <dd>Reduce the amount of information returned</dd>
                           <dt>string <u>&amp;order=&lt;id|name&gt;</u></dt>
                              <dd>Change the return sort order</dd>
                           <dt>string <u>&amp;callback</u></dt>
                              <dd>Used for JSONP responses for XSS</dd>
                          <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                        </dl>
                        </span>
                        <span class="m_e"><strong>Errors</strong><br/>500 Internal Error</span>
                        <strong>Example JSON Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/json<br />
                        Content-Length: 55217<br />
                        [{"id":"32","Name":"Littlejohn Coliseum","Longitude":"-82.846481","Latitude":"34.68036804","Category":"2","Description":""}, <br/>[...]<br/> {"id":"550","Name":"PathNode","Longitude":"-82.8472137451","Latitude":"34.6806435621","Category":"0","Description":"PathNode"}]
                        </span>
                        <br />
                        <strong>Example XML Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/xml<br />
                        Content-Length: 75021<br />
                        &lt;root&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;32&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Littlejohn Coliseum&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.846481&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.68036804&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        [...]<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;550&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;PathNode&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.8472137451&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.6806435621&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;0&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;PathNode&lt;/description&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &lt;/root&gt;
                        </span>
                     </div>
                     </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documentaion page for: getnode()
     */
    function getdocsnode() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     '.$this->_menu().'
                     <div class="method">
                        <span class="m_header">node</span>
                        <span class="request">http://api.hybridoptix.net/node/&lt;node id number&gt;/[args]</span>
                        <span class="m_d"><strong>Description</strong><br/>Get information regarding specific node. Will also return connected nodes and distances to them.</span>
                        <span class="m_a"><strong>Arguments</strong><br/>
                        <dl>
                           <dt>boolean <u>&amp;debug</u></dt>
                              <dd>Pring return output in browser</dd>
                           <dt>boolean <u>&amp;minimal</u></dt>
                              <dd>Reduce the amount of information returned</dd>
                           <dt>string <u>&amp;callback</u></dt>
                              <dd>Used for JSONP responses for XSS</dd>
                          <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                        </dl>
                        </span>
                        <span class="m_e"><strong>Errors</strong><br/>500 Internal Error<br/>306 Unrecognized argument<br/>509 No such node</span>
                        <strong>Example JSON Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/json<br />
                        Content-Length: 384<br />
                        [{"id":"116", "Name":"PathNode", "Longitude":"-82.8365089", "Latitude":"34.67558631", "Category":"0", "Description":"", "Edges":[{"id":"44", "Next":"117", "Distance":"0.022515886", "Handicap":"1"}, {"id":"45", "Next":"125", "Distance":"0.023480353", "Handicap":"1"}, {"id":"46", "Next":"115", "Distance":"0.023967421", "Handicap":"1"}, {"id":"47", "Next":"135", "Distance":"0.02377671", "Handicap":"1"}]}]
                        </span>
                        <br />
                        <strong>Example XML Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/xml<br />
                        Content-Length: 683<br />
                        &lt;root&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;116&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;PathNode&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.8365089&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.67558631&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;0&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;44&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;next&gt;117&lt;/next&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.022515886&lt;/distance&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;45&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;next&gt;125&lt;/next&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.023480353&lt;/distance&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;46&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;next&gt;115&lt;/next&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.023967421&lt;/distance&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;47&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;next&gt;135&lt;/next&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.02377671&lt;/distance&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/edges&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &lt;/root&gt;
                        </span>
                     </div>
                     </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documentation page for: getcategory()
     */
    function getdocscategory() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     '.$this->_menu().'
                     <div class="method">
                       <span class="m_header">category</span>
                       <span class="request">http://api.hybridoptix.net/category/&lt;category id|name&gt;/[args]</span>
                       <span class="m_d"><strong>Description</strong><br/>Get all nodes within a category.</span>
                       <span class="m_a"><strong>Arguments</strong><br/>
                          <dl>
                             <dt>boolean <u>&amp;debug</u></dt>
                                <dd>Pring return output in browser</dd>
                             <dt>boolean <u>&amp;minimal</u></dt>
                                <dd>Reduce the amount of information returned</dd>
                             <dt>string <u>&amp;order=&lt;id|name&gt;</u></dt>
                                <dd>Change the return sort order</dd>
                             <dt>string <u>&amp;callback</u></dt>
                                <dd>Used for JSONP responses for XSS</dd>
                            <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                           </dl>
                        </span>
                        <span class="m_e"><strong>Errors</strong><br/>500 Internal Error<br/>306 Unrecognized argument<br/>510 No nodes in category</span>
                        <strong>Example JSON Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/json<br />
                        Content-Length: 1587<br />
                        [{"id":"32", "Name":"Littlejohn Coliseum", "Longitude":"-82.846481", "Latitude":"34.68036804", "Category":"2", "Description":""}, {"id":"33", "Name":"Memorial Stadium", "Longitude":"-82.84323351", "Latitude":"34.67872353", "Category":"2", "Description":"The Clemson Football stadium,  also known as Death Valley."}, {"id":"64", "Name":"Bowman Field", "Longitude":"-82.83658085", "Latitude":"34.68083768", "Category":"2", "Description":""}, {"id":"72", "Name":"Historic Riggs Field", "Longitude":"-82.83892885", "Latitude":"34.68181378", "Category":"2", "Description":""}, {"id":"107", "Name":"Hoke Sloan Tennis Center", "Longitude":"-82.84053927", "Latitude":"34.68202663", "Category":"2", "Description":""}, {"id":"337", "Name":"Dougs Kingsmore Stadium", "Longitude":"-82.849316597", "Latitude":"34.6787290116", "Category":"2", "Description":""}, {"id":"488", "Name":"Football Practice Fields", "Longitude":"-82.8478896618", "Latitude":"34.6760026858", "Category":"2", "Description":""}, {"id":"492", "Name":"Rugby Field", "Longitude":"-82.8514409065", "Latitude":"34.6793377905", "Category":"2", "Description":"Recreational/Rugby Fields. IPTAY Lot 13"}, {"id":"530", "Name":"Fike Recreation Center", "Longitude":"-82.8419458866", "Latitude":"34.680678853", "Category":"2", "Description":"The on-campus gym,  complete with an indoor track,  natatorium,  climbing wall,  and etcetera."}, {"id":"533", "Name":"Intramural Fields 1", "Longitude":"-82.842310667", "Latitude":"34.6821081193", "Category":"2", "Description":""}, {"id":"534", "Name":"Intramural Fields 2", "Longitude":"-82.843952179", "Latitude":"34.6810846965", "Category":"2", "Description":""}]
                        </span>
                        <br />
                        <strong>Example XML Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/xml<br />
                        Content-Length: 2164<br />
                        &lt;root&gt;
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;32&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Littlejohn Coliseum&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.846481&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.68036804&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;33&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Memorial Stadium&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.84323351&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.67872353&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;The Clemson Football stadium, also known as Death Valley.&lt;/description&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;64&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Bowman Field&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.83658085&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.68083768&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;72&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Historic Riggs Field&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.83892885&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.68181378&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;107&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Hoke Sloan Tennis Center&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.84053927&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.68202663&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;337&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Dougs Kingsmore Stadium&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.849316597&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.6787290116&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;488&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Football Practice Fields&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.8478896618&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.6760026858&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;492&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Rugby Field&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.8514409065&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.6793377905&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;Recreational/Rugby Fields. IPTAY Lot 13&lt;/description&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;530&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Fike Recreation Center&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.8419458866&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.680678853&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;The on-campus gym, complete with an indoor track, natatorium, climbing wall, and etcetera.&lt;/description&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;533&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Intramural Fields 1&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.842310667&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.6821081193&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;534&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Intramural Fields 2&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.843952179&lt;/longitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.6810846965&lt;/latitude&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;2&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt;<br />
                        &lt;/root&gt;
                        </span>
                     </div>
                     </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documentation page for: getlistedges()
     */
    function getdocslistedges() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                        '.$this->_menu().'
                        <div class="method">
                        <span class="m_header">listedges</span>
                        <span class="request">http://api.hybridoptix.net/listedges/[args]</span>
                        <span class="m_d"><strong>Description</strong><br/>Get all edges</span>
                        <span class="m_a"><strong>Arguments</strong><br/>
                        <dl>
                            <dt>boolean <u>&amp;debug</u></dt>
                                <dd>Pring return output in browser</dd>
                            <dt>boolean <u>&amp;minimal</u></dt>
                                <dd>Reduce the amount of information returned</dd>
                            <dt>string <u>&amp;callback</u></dt>
                               <dd>Used for JSONP responses for XSS</dd>
                            <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                        </dl>
                        </span>
                        <span class="m_e"><strong>Errors</strong><br/>500 Internal Error</span>
                        <strong>Example JSON Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/json<br />
                        Content-Length: 127541<br />
                        [{"id":"44", "firstNodeID":"117", "firstNodeLatitude":"34.6753639", "firstNodeLongitude":"-82.83621987", "secondNodeID":"116", "secondNodeLatitude":"34.6753639", "secondNodeLongitude":"-82.83621987", "Distance":"0.022515886", "Handicap":"1"}, <br />[...]<br />  {"id":"652", "firstNodeID":"320", "firstNodeLatitude":"34.6732233293", "firstNodeLongitude":"-82.8421711922", "secondNodeID":"342", "secondNodeLatitude":"34.6732233293", "secondNodeLongitude":"-82.8421711922", "Distance":"0.0869321166841", "Handicap":"1"}]
                        </span>
                        <br />
                        <strong>Example XML Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/xml<br />
                        Content-Length: 204833<br />
                        &lt;root&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;edge&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;44&lt;/id&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnodeid&gt;117&lt;/firstnodeid&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnodelatitude&gt;34.6753639&lt;/firstnodelatitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnodelongitude&gt;-82.83621987&lt;/firstnodelongitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnodeid&gt;116&lt;/secondnodeid&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnodelatitude&gt;34.6753639&lt;/secondnodelatitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnodelongitude&gt;-82.83621987&lt;/secondnodelongitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.022515886&lt;/distance&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/edge&gt;<br />
                        [...]
                        <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;edge&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;652&lt;/id&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnodeid&gt;320&lt;/firstnodeid&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnodelatitude&gt;34.6732233293&lt;/firstnodelatitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnodelongitude&gt;-82.8421711922&lt;/firstnodelongitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnodeid&gt;342&lt;/secondnodeid&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnodelatitude&gt;34.6732233293&lt;/secondnodelatitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnodelongitude&gt;-82.8421711922&lt;/secondnodelongitude&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.0869321166841&lt;/distance&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt; <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/edge&gt; <br />
                        &lt;/root&gt;
                        </span>
                    </div>
                    </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documentation page for: getlistcategory()
     */
    function getdocslistcategory() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     '.$this->_menu().'
                     <div class="method">
                        <span class="m_header">listedges</span>
                        <span class="request">http://api.hybridoptix.net/listcategory/[args]</span>
                        <span class="m_d"><strong>Description</strong><br/>Get all categories</span>
                        <span class="m_a"><strong>Arguments</strong><br/>
                        <dl>
                            <dt>boolean <u>&amp;debug</u></dt>
                                <dd>Pring return output in browser</dd>
                            <dt>string <u>&amp;callback</u></dt>
                                <dd>Used for JSONP responses for XSS</dd>
                            <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                        </dl>
                        </span>
                        <span class="m_e"><strong>Errors</strong><br/>500 Internal Error</span>
                        <strong>Example JSON Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/json<br />
                        Content-Length: 233<br />
                        [{"id":"1", "Name":"Academic"}, {"id":"2", "Name":"Athletic"}, {"id":"3", "Name":"Administrative"}, {"id":"4", "Name":"Dining"}, {"id":"5", "Name":"Housing"}, {"id":"6", "Name":"Visitor"}, {"id":"7", "Name":"Parking"}, {"id":"8", "Name":"Gardens"}]
                        </span>
                        <br />
                        <strong>Example XML Response</strong>
                        <span class="m_r">
                        HTTP/1.1 200 OK<br />
                        Content-Type: application/xml<br />
                        Content-Length: 555<br />
                        &lt;root&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;1&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Academic&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;2&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Athletic&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;3&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Administrative&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;4&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Dining&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;5&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Housing&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;6&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Visitor&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;7&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Parking&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;8&lt;/id&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Gardens&lt;/name&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&lt;/category&gt;<br />
                        &lt;/root&gt;
                        </span>
                    </div>
                    </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documentation page for: getedge()
     */
    function getdocsedge() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     '.$this->_menu().'
                      <div class="method">
                         <span class="m_header">edge</span>
                         <span class="request">http://api.hybridoptix.net/edge/&lt;edge id number&gt;/[args]</span>
                         <span class="m_d"><strong>Description</strong><br/>Get information regarding specific edge.</span>
                         <span class="m_a"><strong>Arguments</strong><br/>
                         <dl>
                            <dt>boolean <u>&amp;debug</u></dt>
                               <dd>Pring return output in browser</dd>
                            <dt>string <u>&amp;callback</u></dt>
                               <dd>Used for JSONP responses for XSS</dd>
                            <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                         </dl>
                         </span>
                         <span class="m_e"><strong>Errors</strong><br/>500 Internal Error<br/>306 Unrecognized argument<br/>508 No such edge</span>
                         <strong>Example JSON Response</strong>
                         <span class="m_r">
                         HTTP/1.1 200 OK<br />
                         Content-Type: application/json<br />
                         Content-Length: 90<br />
                         [{"id":"58", "firstnode":"120", "secondnode":"121", "Distance":"0.010026896", "Handicap":"1"}]
                         </span>
                         <br />
                         <strong>Example XML Response</strong>
                         <span class="m_r">
                         HTTP/1.1 200 OK<br />
                         Content-Type: application/xml<br />
                         Content-Length: 210<br />
                         &lt;root&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&lt;edge&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;58&lt;/id&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;firstnode&gt;120&lt;/firstnode&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;secondnode&gt;121&lt;/secondnode&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;0.010026896&lt;/distance&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;handicap&gt;1&lt;/handicap&gt;<br />
                         &nbsp;&nbsp;&nbsp;&nbsp;&lt;/edge&gt;<br />
                         &lt;/root&gt;<br />
                         </span>
                      </div>
                     </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

    /*
     * Documentation page for: getclosest()
     */
    function getdocsclosest() {
        $this->_header();
        echo '
               <div id="container">
                  <div id="request">
                     <fieldset>
                     '.$this->_menu().'
                      <div class="method">
                         <span class="m_header">closest</span>
                         <span class="request">http://api.hybridoptix.net/closest/&lt;latitude&gt;/&lt;longitude&gt;/[args]</span>
                         <span class="m_d"><strong>Description</strong><br/>Takes the provided GPS coordinates and returns the closest node(s). Distance is returned in feet and bearing is returned as a compass heading.</span>
                         <span class="m_a"><strong>Arguments</strong><br/>
                         <dl>
                            <dt>boolean <u>&amp;debug</u></dt>
                               <dd>Pring return output in browser</dd>
                            <dt>string <u>&amp;callback</u></dt>
                               <dd>Used for JSONP responses for XSS</dd>
                            <dt>string <u>&amp;category=&lt;first|main|#&gt;|destination</u></dt>
                               <dd><strong>first</strong> will return the very first node(s) from the given point</dd>
                               <dd><strong>main</strong> will return the very first node(s) that is not a pathnode from the given point</dd>
                               <dd><strong>#</strong> (meaning numeric category id) will return the very first node(s) within that category from the given point</dd>
                            <dt>integer <u>&amp;destination</u></dt>
                               <dd>Will return distance and bearing to the desired end point</dd>
                            <dt>string <u>&amp;type=&lt;xml|json&gt;</u></dt>
                              <dd>Change the response type to XML</dd>
                         </dl>
                         </span>
                         <span class="m_e"><strong>Errors</strong><br/>500 Internal Error<br/>306 Unrecognized argument<br/>509 No such node<br/>510 No nodes in category</span>
                         <strong>Example Point</strong><br />
                         <img src="http://api.hybridoptix.net/includes/map.png" />
                         http://api.hybridoptix.net/closest/34.676179284768864/-82.8353906732483<br /><br />
                         <strong>Example JSON Response</strong>
                         <span class="m_r">
                         HTTP/1.1 200 OK<br />
                         Content-Type: application/json<br />
                         Content-Length: 172<br />
                         [{"id":"37", "name":"Cooper Library", "longitude":"-82.83645225", "latitude":"34.67663793", "category":"1", "description":"Clemson\'s Library", "distance":"360", "bearing":"293"}]
                         </span>
                         <br />
                         <strong>Example XML Response</strong>
                         <span class="m_r">
                         HTTP/1.1 200 OK<br />
                         Content-Type: application/xml<br />
                         Content-Length: 317<br />
                         &lt;root&gt;<br />
                            &nbsp;&nbsp;&nbsp;&nbsp;&lt;node&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;37&lt;/id&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Cooper Library&lt;/name&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;longitude&gt;-82.83645225&lt;/longitude&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;latitude&gt;34.67663793&lt;/latitude&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&gt;1&lt;/category&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;Clemson\'s Library&lt;/description&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;distance&gt;360&lt;/distance&gt; <br />
                               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bearing&gt;293&lt;/bearing&gt; <br />
                            &nbsp;&nbsp;&nbsp;&nbsp;&lt;/node&gt; <br />
                         &lt;/root&gt;
                         </span>
                      </div>
                     </fieldset>
                  </div>
               </div>
            </body>
            </html>';
    }

}
?>